package com.xiaoyu.izf.aspect;//package com.xiaoyu.izf.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

@Aspect
@Component
public class FieldSetAspect {

    @Autowired
    private ApplicationContext context;

    /**
     * UserInfo
     * vipType=1
     *
     * @FieldSet(beanClass = VipInfoDao.class,method = "findById",param = "vipType",source = "vipName")
     * vipName
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("@annotation(FieldSetNotify)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        Object object = pjp.proceed();
        Class<?> cl = object.getClass();
        Field[] fields = cl.getDeclaredFields();
        for (Field field : fields) {
            FieldSet fieldSet = field.getDeclaredAnnotation(FieldSet.class);
            if (fieldSet==null){
                continue;
            }

            Class<?> beanClass = fieldSet.beanClass();
            Field argField = cl.getDeclaredField(fieldSet.param());
            Class<?> argType = argField.getType();
            setFieldAccess(argField);
            Object arg = argField.get(object);
            Method method = beanClass.getDeclaredMethod(fieldSet.method(),argType);
            Object sourceObj = method.invoke(context.getBean(beanClass),arg);
            if (sourceObj!=null){
                Field sourceField = sourceObj.getClass().getDeclaredField(fieldSet.source());
                setFieldAccess(sourceField);
                Object sourceArg = sourceField.get(sourceObj);

                setFieldAccess(field);
                field.set(object,sourceArg);
            }
        }
        return object;
    }

    private void setFieldAccess(Field field){
        field.setAccessible(true);
    }
}
